﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Globalization;
using System.Threading;
using System.Text.RegularExpressions;

namespace JYM.Common
{
    /// <summary>
    /// 日期时间工具类
    /// </summary>
    public class DateTimeHelper
    {

        /// <summary>
        /// 合并日期和时间
        /// </summary>
        /// <param name="p_DateValue">被合并的日期</param>
        /// <param name="p_TimeValue">被合并的时间</param>
        /// <returns>合并后的日期时间</returns>
        public static DateTime DateAndTime(DateTime p_DateValue, DateTime p_TimeValue)
        {
            DateTime time2;
            time2 = new DateTime(p_DateValue.Year, p_DateValue.Month, p_DateValue.Day, p_TimeValue.Hour, p_TimeValue.Minute, p_TimeValue.Second);
            return time2;
        }


        /// <summary>
        /// 获取指定日期最晚日期时间（当天的23:59:59）
        /// </summary>
        /// <param name="p_DateValue"></param>
        /// <returns></returns>
        public static DateTime DateEndOfDay(DateTime p_DateValue)
        {
            return Convert.ToDateTime((p_DateValue.ToString("yyyy-MM-dd") + " 23:59:59"));
        }

        /// <summary>
        /// 获取指定日期最早日期时间（当天的00:00:00）
        /// </summary>
        /// <param name="p_DateValue"></param>
        /// <returns></returns>
        public static DateTime DateStartOfDay(DateTime p_DateValue)
        {
            return Convert.ToDateTime((p_DateValue.ToString("yyyy-MM-dd") + " 00:00:00"));
        }

        /// <summary>
        /// 获取指定日期所在周的开始第一天的日期（以当前系统设置的一周开始星期几为标准）
        /// </summary>
        /// <param name="p_Date">指定日期</param>
        /// <returns>DateTime</returns>
        public static DateTime GetWeekStart(DateTime p_Date)
        {
            CultureInfo info = Thread.CurrentThread.CurrentCulture;
            DayOfWeek firstday = info.DateTimeFormat.FirstDayOfWeek;
            DayOfWeek today = info.Calendar.GetDayOfWeek(p_Date);

            int diff = 0;
            if (firstday != DayOfWeek.Sunday && today == DayOfWeek.Sunday)
            {
                diff = 6;
            }
            else
            {
                diff = today - firstday;
            }

            return p_Date.Date.AddDays(-diff);
        }

        /// <summary>
        /// 获取指定日期所在周的开始最后一天的日期（以当前系统设置的一周开始星期几为标准）
        /// </summary>
        /// <param name="p_Date">指定日期</param>
        /// <returns>DateTime</returns>
        public static DateTime GetWeekEnd(DateTime p_Date)
        {
            return GetWeekStart(p_Date.Date).AddDays(-7);
        }

        /// <summary>
        /// 获取指定日期增加指定工作日后的日期（周六周日为非工作日）
        /// </summary>
        /// <param name="p_Date">当前日期</param>
        /// <param name="p_Days">工作日</param>
        /// <returns>DateTime</returns>
        public static DateTime AddBusinessDays(DateTime p_Date, int p_Days)
        {
            double sign = Convert.ToDouble(Math.Sign(p_Days));
            int unsignedDays = Math.Sign(p_Days) * p_Days;

            for (int i = 0; i < unsignedDays; i++)
            {
                do
                {
                    p_Date = p_Date.AddDays(sign);
                }
                while (p_Date.DayOfWeek == DayOfWeek.Saturday || p_Date.DayOfWeek == DayOfWeek.Sunday);
            }

            return p_Date;
        }

        /// <summary>
        /// 返回日期之间相差的天数（一般日期一小于日期二）
        /// </summary>
        /// <param name="p_Date1">日期一</param>
        /// <param name="p_Date2">日期二</param>
        /// <returns></returns>
        public static int DiffDateTimeByDays(string p_Date1, string p_Date2)
        {
            return DiffDateTimeByDays(Convert.ToDateTime(p_Date1), Convert.ToDateTime(p_Date2));
        }
        /// <summary>
        /// 返回日期之间相差的天数（一般日期一小于日期二）
        /// </summary>
        /// <param name="p_Date1">日期一</param>
        /// <param name="p_Date2">日期二</param>
        /// <returns></returns>
        public static int DiffDateTimeByDays(DateTime p_Date1, DateTime p_Date2)
        {
            DateTime d1 = Convert.ToDateTime(p_Date1);
            DateTime d2 = Convert.ToDateTime(p_Date2);
            TimeSpan s = d2 - d1;
            return Convert.ToInt32(s.TotalDays);
        }

        /// <summary>
        /// 把YYYYMMDD的日期字串格式转日期格式
        /// </summary>
        /// <param name="p_StrDay">YYYYMMDD日期字串</param>
        /// <returns>DateTime</returns>
        public static DateTime YYYYMMDDToDate(string p_StrDay)
        {

            DateTime date = default(DateTime);

            if (p_StrDay.Length == 8)
            {
                date = new DateTime(ConvertHelper.SafeToInt32(p_StrDay.Substring(0, 4)), ConvertHelper.SafeToInt32(p_StrDay.Substring(4, 2)), ConvertHelper.SafeToInt32(p_StrDay.Substring(4, 2)));
            }

            return date;

        }

        /// <summary>
        /// 把HHMMSS的时间格式字串转化成日期
        /// </summary>
        /// <param name="p_StrTime">HHMMSS时间字串</param>
        /// <returns>DateTime</returns>
        public static DateTime HHMMSSToTime(string p_StrTime)
        {

            DateTime time = default(DateTime);

            object obj1 = time.ToString();
            if (p_StrTime.Length == 6)
            {
                time = new DateTime(0x6d9, 1, 1, ConvertHelper.SafeToInt32(p_StrTime.Substring(0, 2)), ConvertHelper.SafeToInt32(p_StrTime.Substring(3, 2)), ConvertHelper.SafeToInt32(p_StrTime.Substring(5, 2)));
            }

            return time;

        }


        /// <summary>
        /// 指定时间段是否包含指定的DayOfWeek
        /// </summary>
        /// <param name="p_DayOfWeek">指定一周的某一天</param>
        /// <param name="p_DateFrom">开始日期</param>
        /// <param name="p_DateTo">结束日期</param>
        /// <param name="p_bExcludeEndDate">是否排除结束日期</param>
        /// <returns></returns>
        public static bool IsDayOfWeekInRange(DayOfWeek p_DayOfWeek, DateTime p_DateFrom, DateTime p_DateTo, bool p_bExcludeEndDate)
        {

            DateTime tempDate = p_DateFrom;

            //if(dateFrom> dateTo){ throw new ArgumentException(String.Format("dateFrom {0} must be less or equal than dateTo {1}",dateFrom,  dateTo)};

            DateTime dateEnd = p_bExcludeEndDate ? p_DateTo.AddDays(-1) : p_DateTo;

            while (tempDate <= dateEnd)
            {

                if (tempDate.DayOfWeek == p_DayOfWeek)

                    return true;

                tempDate = tempDate.AddDays(1);

            }

            return false;

        }


        #region  获取指定日期下一周指定周几的相关方法
       
        /// <summary>
        /// 获取下一个出现的未来的日子里
        /// </summary>
        /// <param name="p_Value">指定日期</param>
        /// <param name="p_DayOfWeek">要查找到接下来一周的某一天</param>
        /// <returns>DateTime</returns>
        public static DateTime GetNextOccurenceOfDay(DateTime p_Value, DayOfWeek p_DayOfWeek)
        {
            return GetNextOccurenceOfDay(p_Value, p_DayOfWeek, false);
        }
        /// <summary>
        /// 获取下一个出现的未来的日子里s
        /// </summary>
        /// <param name="p_Value">指定日期</param>
        /// <param name="p_DayOfWeek">要查找到接下来一周的某一天</param>
        /// <param name="p_bIncludeStartDay">是否包括开始日期</param>
        /// <returns>DateTime</returns>
        public static DateTime GetNextOccurenceOfDay(DateTime p_Value, DayOfWeek p_DayOfWeek, bool p_bIncludeStartDay)
        {

            int daysToAdd = p_DayOfWeek - p_Value.DayOfWeek;

            int nMinDifference = p_bIncludeStartDay ? 0 : 1;

            if (daysToAdd < nMinDifference)
            {
                daysToAdd += 7;
            }

            return p_Value.AddDays(daysToAdd);

        }

        /// <summary>
        /// 获取下一个星期一
        /// </summary>
        /// <param name="p_Value">指定日期</param>
        public static DateTime NextMonday(DateTime p_Value)
        {
            return GetNextOccurenceOfDay(p_Value, DayOfWeek.Monday);
        }

        /// <summary>
        /// 获取下一个星期二
        /// </summary>
        /// <param name="p_Value">指定日期</param>
        public static DateTime NextTuesday(DateTime p_Value)
        {
            return GetNextOccurenceOfDay(p_Value, DayOfWeek.Tuesday);
        }

        /// <summary>
        /// 获取下一个星期三
        /// </summary>
        /// <param name="p_Value">指定日期</param>
        public static DateTime NextWednesday(DateTime p_Value)
        {
            return GetNextOccurenceOfDay(p_Value, DayOfWeek.Wednesday);
        }

        /// <summary>
        /// 获取最近的一个星期四
        /// </summary>
        /// <param name="p_Value">指定日期</param>
        /// <returns>DateTime</returns>
        public static DateTime NextThursday(DateTime p_Value)
        {
            return GetNextOccurenceOfDay(p_Value, DayOfWeek.Thursday);
        }

        /// <summary>
        ///获取下一个星期五
        /// </summary>
        /// <param name="p_Value">指定日期</param>
        public static DateTime NextFriday(DateTime p_Value)
        {
            return GetNextOccurenceOfDay(p_Value, DayOfWeek.Friday);
        }

        /// <summary>
        /// 获取下一个星期六
        /// </summary>
        /// <param name="p_Value">指定日期</param>
        public static DateTime NextSaturday(DateTime p_Value)
        {
            return GetNextOccurenceOfDay(p_Value, DayOfWeek.Saturday);
        }

        /// <summary>
        /// 获取下一个星期日
        /// </summary>
        /// <param name="p_Value">指定日期</param>
        public static DateTime NextSunday(DateTime p_Value)
        {
            return GetNextOccurenceOfDay(p_Value, DayOfWeek.Sunday);
        }





        /// <summary>
        /// 获取最近的一个星期一
        /// </summary>
        /// <param name="p_Value">指定日期</param>
        /// <returns>DateTime</returns>
        public static DateTime ClosestMonday(DateTime p_Value)
        {
            return GetNextOccurenceOfDay(p_Value, DayOfWeek.Monday, true);
        }

        /// <summary>
        /// 获取最近的一个星期二
        /// </summary>
        /// <param name="p_Value">指定日期</param>
        /// <returns>DateTime</returns>
        public static DateTime ClosestTuesday(DateTime p_Value)
        {
            return GetNextOccurenceOfDay(p_Value, DayOfWeek.Tuesday, true);
        }

        /// <summary>
        /// 获取最近的一个星期三
        /// </summary>
        /// <param name="p_Value">指定日期</param>
        /// <returns>DateTime</returns>
        public static DateTime ClosestWednesday(DateTime p_Value)
        {
            return GetNextOccurenceOfDay(p_Value, DayOfWeek.Wednesday, true);
        }

        /// <summary>
        /// 获取最近的一个星期四
        /// </summary>
        /// <param name="p_Value">指定日期</param>
        /// <returns>DateTime</returns>
        public static DateTime ClosestThursday(DateTime p_Value)
        {
            return GetNextOccurenceOfDay(p_Value, DayOfWeek.Thursday, true);
        }

        /// <summary>
        /// 获取最近的一个星期五
        /// </summary>
        /// <param name="p_Value">指定日期</param>
        /// <returns>DateTime</returns>
        public static DateTime ClosestFriday(DateTime p_Value)
        {
            return GetNextOccurenceOfDay(p_Value, DayOfWeek.Friday, true);
        }

        /// <summary>
        /// 获取最近的一个星期六
        /// </summary>
        /// <param name="p_Value">指定日期</param>
        /// <returns>DateTime</returns>
        public static DateTime ClosestSaturday(DateTime p_Value)
        {
            return GetNextOccurenceOfDay(p_Value, DayOfWeek.Saturday, true);
        }

        /// <summary>
        /// 获取最近的一个星期日
        /// </summary>
        /// <param name="p_Value">指定日期</param>
        /// <returns>DateTime</returns>
        public static DateTime ClosestSunday(DateTime p_Value)
        {
            return GetNextOccurenceOfDay(p_Value, DayOfWeek.Sunday, true);
        }

        #endregion

    }
}
